const httpServer = require("http").createServer();
const io = require("socket.io")(httpServer);
const redis = require("redis");
const redisClient = redis.createClient(6379, "127.0.0.1");
const userMap = new Map();
const roomKey = "meeting-room::";

httpServer.listen(18080, async () => {
	console.log("服务器启动成功 *:18080");
	await redisClient.connect();
});

redisClient.on("error", (err) => {
	console.log("redisClient connect Error ", err);
});

io.on("connection", async (socket) => {
	await onListener(socket);
});

function returnResponseMsg(type, msg, status = 200, data = null) {
	return {
		type: type,
		msg: msg,
		status: status,
		data: data,
	};
}

function getUrlParams(url, queryName) {
	let query = decodeURI(url.split("?")[1]);
	let vars = query.split("&");
	for (let i = 0; i < vars.length; i++) {
		let pair = vars[i].split("=");
		if (pair[0] === queryName) {
			return pair[1];
		}
	}
	return null;
}

async function getAllUserByRoomNumber(roomId) {
	return await redisClient.hGetAll(`${roomKey}${roomId}`);
}

function oneToOne(uid, msg) {
	let socket = userMap.get(uid);
	if (socket) {
		socket.emit("msg", msg);
	} else {
		console.log(uid + "用户不在线");
	}
}

async function oneToRoomMany(roomId, msg) {
	let uList = await getAllUserByRoomNumber(roomId);
	for (const uid in uList) {
		oneToOne(uid, msg);
	}
}

async function onListener(socket) {
	const url = socket.client.request.url;
	const userId = getUrlParams(url, "userId");
	const roomId = getUrlParams(url, "roomId");
	const nickname = getUrlParams(url, "nickname");
	const pub = getUrlParams(url, "pub");

	// 有新用户连接, 则加入哈希表中
	userMap.set(userId, socket);

	// 有新用户加入, 则缓存到 redis 哈希表中, 并且通知所有用户
	if (roomId) {
		await redisClient.hSet(
			`${roomKey}${roomId}`,
			userId,
			JSON.stringify({ userId, roomId, nickname, pub })
		);
		oneToRoomMany(roomId, returnResponseMsg("join", `${userId}join then room`, 200, { userId, roomId, nickname, pub }));
	}

	// 有新消息, 则根据房间号, 通知所有用户
	socket.on("msg", async (data) => {
		await oneToRoomMany(roomId, data);
	});

	// 用户断开连接, 则从哈希表中移除, 并通知所有用户
	socket.on("disconnect", () => {
		console.log(`client uid: ${userId} roomId: ${roomId} offline`);
		userMap.delete(userId);
		if (roomId) {
			redisClient.hDel(`${roomKey}${roomId}`, userId);
			oneToRoomMany(roomId, returnResponseMsg("leave", `${userId} leave the room`, 200, { userId, roomId, nickname, pub }));
		}
	});

	// 根据房间号返回所有用户信息
	socket.on("roomUserList", async (data) => {
		socket.emit("roomUserList", await getAllUserByRoomNumber(data["roomId"]));
	});

	// 协商中转
	socket.on("call", (data) => {
		let targetUid = data["targetUid"];
		if (userMap.get(targetUid)) {
			oneToOne(targetUid, returnResponseMsg("call", "远程呼叫", 200, data));
		} else {
			console.log(targetUid + "不在线");
		}
	});
	socket.on("candidate", (data) => {
		let targetUid = data["targetUid"];
		if (userMap.get(targetUid)) {
			oneToOne(targetUid, returnResponseMsg("candidate", "ice candidate", 200, data));
		} else {
			console.log(targetUid + "不在线");
		}
	});
	socket.on("offer", (data) => {
		let targetUid = data["targetUid"];
		if (userMap.get(targetUid)) {
			oneToOne(targetUid, returnResponseMsg("offer", "rtc offer", 200, data));
		} else {
			console.log(targetUid + "不在线");
		}
	});
	socket.on("answer", (data) => {
		let targetUid = data["targetUid"];
		if (userMap.get(targetUid)) {
			oneToOne(targetUid, returnResponseMsg("answer", "rtc answer", 200, data));
		} else {
			console.log(targetUid + "不在线");
		}
	});
}
